﻿using System;
using System.Collections;
using System.Data;
using capaDatos;

namespace accesoDatos
{
    /**
     * EntidadAlmacenable: representa toda entidad que debe ser almacenada en una tabla de la BD, y
     * define una serie de atributos y métodos básicos que trabajan sobre éstos, para generalizar
     * las operaciones de interacción con la BD.
     *
     * author Nanu
     * fecha 31-enero-2013
     */
    public class EntidadAlmacenable
    {
        protected int id = 0;                        // Valor que identifica unívocamente al elemento actual
        protected String nombreColumnaID = "id";     // Nombre de la columna en la tabla de la BD donde se guarda el identificador único. Default: 'id'
        protected Boolean idAutoGenerado = true;     // Indica si el identificador unívoco se genera automáticamente (true) o no (false). Default: true
        protected String nombreTablaBD = "";         // Nombre de la tabla que almacena la información representada por la entidad

        protected ManejadorBD manejadorBD;           // Objeto que interactúa con la capa de acceso a datos
        protected String error = "";
        protected Hashtable relacionesOtrasTablas = new Hashtable();

        public EntidadAlmacenable()
        {
            this.manejadorBD = Conexion_Manejador.getManejadorBD();
        }

        public String getError()
        {
            return this.error;
        }

        /**
         * Método estático que obtiene una lista de registros de una tabla particular, pudiéndose aplicar filtros a la 
         * consulta correspondiente. Devuelve un objeto DataSet con el resultado de la consulta.
         */
        public static DataTable listarElementos(String nombreTabla)
        {
            String[] columnasFiltros = new String[] { }, valoresFiltros = new String[] { };
            int registroInicial = -1, registroFinal = -1;
            string[] orden = new string[] { };
            return listarElementos(nombreTabla, columnasFiltros, valoresFiltros, orden, registroInicial, registroFinal);
        }

        public static DataTable listarElementos(String nombreTabla, String[] columnasFiltros, String[] valoresFiltros)
        {
            int registroInicial = -1, registroFinal = -1;
            string[] orden = new string[] { };
            return listarElementos(nombreTabla, columnasFiltros, valoresFiltros, orden, registroInicial, registroFinal);
        }

        public static DataTable listarElementos(String nombreTabla, String[] columnasFiltros, String[] valoresFiltros, String[] orden)
        {
            int registroInicial = -1, registroFinal = -1;
            return listarElementos(nombreTabla, columnasFiltros, valoresFiltros, orden, registroInicial, registroFinal);
        }

        public static DataTable listarElementos(String nombreTabla, String[] columnasFiltros, String[] valoresFiltros, String[] orden, int registroInicial, int registroFinal)
        {
            ManejadorBD objManejadorBD = new ManejadorBD();
            DataSet resultado = objManejadorBD.obtenerDatos(nombreTabla, columnasFiltros, valoresFiltros, orden, registroInicial, registroFinal);
            DataTable tabla;
            if (resultado.Tables.Count > 0) tabla = resultado.Tables[0];
            else tabla = new DataTable("tabla");

            return tabla;
        }

        protected DataRow buscarElemento(int id)
        {
            DataSet resultado = manejadorBD.obtenerDatos(string.Format("SELECT * FROM {0} WHERE {1} = '{2}'", this.nombreTablaBD, this.nombreColumnaID, this.id));
            
            DataTable tabla;
            if (resultado.Tables.Count > 0) tabla = resultado.Tables[0];
            else tabla = new DataTable("tabla");

            DataRow filaResultado;
            if (tabla.Rows.Count > 0) // Si se encontrasen filas en el resultado, busco la primera y obtengo los datos
                filaResultado = tabla.Rows[0];
            else filaResultado = null;

            this.error = manejadorBD.Error;
            return filaResultado;
        }

        public static bool existeElemento(string tablaBD, string[] columnasFiltros, string[] valoresFiltros)
        {
            DataTable resultado = EntidadAlmacenable.listarElementos(tablaBD, columnasFiltros, valoresFiltros);
            if (resultado.Rows.Count > 0) return true;
            else return false;
        }

        public static bool existe(int id, string nombre, string tablaBD)
        {
            string[] camposFiltro = new string[] { "id", "nombre" };
            string[] valoresFiltro = new string[] { "E" + id.ToString(), "E" + nombre.Trim() };

            return existeElemento(tablaBD, camposFiltro, valoresFiltro);
        }

        public static bool existe(string nombre, string tablaBD)
        {
            string[] camposFiltro = new string[] { "nombre" };
            string[] valoresFiltro = new string[] { "E" + nombre.Trim() };

            return existeElemento(tablaBD, camposFiltro, valoresFiltro);
        }

        /* Este método es protected ya que sólo puede ser invocado por las clases hijas, las cuales deben definir previamente el conjunto de
         * valores actuales que se deben almacenar en la tabla de la BD que corresponda antes de llamarlo.
         */
        protected String guardarElemento(String[] columnas, String[] valores)
        {
            if (this.id == 0) // Se trata de un nuevo elemento
            {
                this.manejadorBD.ejecutarABM(TipoOperacionABM.ALTA, this.nombreTablaBD, columnas, valores, new String[] { }, new String[] { }, this.idAutoGenerado);
                this.id = this.manejadorBD.UltimoIdGenerado;
            }
            else // Actualización de un elemento
            { this.manejadorBD.ejecutarABM(TipoOperacionABM.MODIFICACION, this.nombreTablaBD, columnas, valores, new String[] { this.nombreColumnaID }, new String[] { this.id.ToString() }); }

            this.error = this.manejadorBD.Error;
            return this.error;
        }

        public String borrarElemento()
        {
            bool existenRegistrosRelacionados = false;

            int cantidadRegistros = 0;
            string tablaRelacion = "", columnaRelacion = "";
            foreach (DictionaryEntry relacion in this.relacionesOtrasTablas)
            {
                tablaRelacion = relacion.Key.ToString();
                columnaRelacion = relacion.Value.ToString();
                string consultaSQL = string.Format("SELECT COUNT(*) AS cantidad FROM {0} WHERE {1} = '{2}'", tablaRelacion, columnaRelacion, this.id);
                cantidadRegistros = this.manejadorBD.contarRegistros(consultaSQL);
                if (cantidadRegistros > 0)
                {
                    existenRegistrosRelacionados = true;
                    break;
                }
            }

            if (!existenRegistrosRelacionados)
            {
                this.manejadorBD.ejecutarABM(TipoOperacionABM.BAJA, this.nombreTablaBD, new String[] { }, new String[] { }, new String[] { this.nombreColumnaID }, new String[] { this.id.ToString() });
                this.error = this.manejadorBD.Error;
            }
            else error = "No se puede borrar el elemento ya que existen datos que dependen del mismo en la tabla " + tablaRelacion + ".";

            return this.error;
        }
    }
}
